home *** CD-ROM | disk | FTP | other *** search
/ Fritz: All Fritz / All Fritz.zip / All Fritz / FILES / PROGBLER / WHIZZARD.LZH / DEBUGFIX.TXT < prev    next >
Text File  |  1984-07-11  |  11KB  |  380 lines

  1.  
  2.  
  3. File: DEBUGFIX.TXT             On: CLUBware Software Diskette #1
  4. Author: Stan Radzio
  5. Copyright (C) 1984. RAYHAWK AUTOMATION, N W, INC.
  6.  
  7. This patch to DOS 2.0 DEBUG prevents system lockup during trace
  8. operations.
  9.  
  10. While single stepping through programs with the DEBUG T (trace)
  11. command, a timer interrupt may occur at the moment DEBUG transfers
  12. control to the next program instruction to execute.  Instead of single
  13. stepping the next instruction from the user's program, DEBUG begins
  14. execution of the first instruction within the timer interrupt routine:
  15. an STI at location F000:FEA5 .
  16.  
  17. When this happens, DEBUG displays the current register contents, the
  18. STI instruction from the timer interrupt routine, the DEBUG command
  19. prompt (-), then waits for a command from the keyboard.
  20. Unfortunately, the timer interrupt is an external hardware interrupt
  21. prioritized by the 8259 interrupt controller chip present on the PC
  22. motherboard.  Once a timer interrupt occurs, no further external
  23. interrupts are allowed by the 8259 until an end-of-interrupt signal is
  24. sent to the 8259.  Characters are transmitted from the keyboard to the
  25. PC by means of an external interrupt.  DEBUG is left in a state where
  26. it is waiting for a command from the keyboard while the keyboard
  27. cannot communicate with the PC because external interrupts have been
  28. temporarily disabled by the 8259.  The only recovery possible at this
  29. point is to power down the PC, then power up for a cold reboot.
  30.  
  31. We have seen one previous fix to this problem.    The circumvention is
  32. to disable timer interrupts while tracing program execution.  From
  33. within DEBUG, use the I (in) command to retrieve the current contents
  34. of port 21h.  This is the mask used by the 8259 to determine which
  35. external interrupts will be passed through to the 8088 CPU.
  36.  
  37.     -I  21
  38.     BC
  39.     -
  40.  
  41. The normal mask is BC allowing keyboard interrupts, disk controller
  42. interrupts, and timer interrupts.  Change the mask to BD to prevent
  43. timer interrupts.
  44.  
  45.     -O  21    BD
  46.     -
  47.  
  48. There is a major problem with this process other than inaccuracies in
  49. the time of day.  The timer interrupt service routine is used by the
  50. BIOS to turn off the diskette drive motor after diskette operations.
  51. With the timer interrupts masked off, the next diskette I/O will start
  52. the motor and the motor will remain on indefinitely.
  53.  
  54. A true fix for this problem must be a modification to DEBUG itself.
  55. Once the problem occurs, the keyboard is silenced and there is no
  56. opportunity to invoke special service routines to bail us out.
  57.  
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69. File: DEBUGFIX.TXT                    Page 2
  70.  
  71.  
  72.  
  73. One modification to DEBUG would be to have DEBUG send an
  74. end-of-interrupt signal to the 8259 just before requesting the next
  75. command from the keyboard.  However, the BIOS routines have
  76. initialized the 8259 to recognize a non-specific end-of-interrupt.
  77. The end-of-interrupt signal is a 20h sent to port 20h and means an end
  78. to the current external interrupt whatever it may be.  The possibility
  79. of DEBUG clearing an external interrupt not related to the timer is
  80. very small with the current hardware and software available for the
  81. PC.  As for the future...?
  82.  
  83. Without access to the source code for DEBUG, we have developed a
  84. modification to DEBUG which eliminates the problem and is completely
  85. safe.  Our modification is to compare the address of the interrupted
  86. routine to the list of hardware interrupt service routines in low
  87. memory.  If the address matches, we know that we collided with the
  88. interrupt and must act quickly to prevent the system from becoming
  89. deaf and mute.
  90.  
  91. When the timer interrupts the code being traced, DEBUG is given
  92. control with the stack in this state:
  93.  
  94.     SP     FEA5  - offset of timer interrupt routine
  95.     SP+2     F000  - segment of timer interrupt routine
  96.     SP+4     flags - saved copy of timer's flags
  97.              (trap flag bit is set)
  98.     SP+6     XXXX  - offset of user code being traced
  99.     SP+8     ZZZZ  - segment of user code being traced
  100.     SP+10     flags - saved copy of user's flags
  101.              (trap flag bit is set)
  102.  
  103. Our modification looks at the stack to see the F000:FEA5 and
  104. recognizes we are in trouble.  To extricate ourselves, we clear the
  105. trap flag bit from SP+4, the timer's flags, and perform an IRET to
  106. return control to the timer interrupt routine.    The timer code updates
  107. his count of the seconds in the day, turns the diskette motor off if
  108. needed, signals an end-of-interrupt to the 8259 (very important to
  109. us), then performs an IRET which transfers control to our code at
  110. SP+6.  The trap flag at SP+10 is still set so a single step interrupt
  111. again occurs and DEBUG trace picks up normally as if nothing strange
  112. had happened.  A similar process occurs when any external hardware
  113. interrupt other than the timer occurs during the trace command.
  114.  
  115. The code we wish to add to DEBUG should be invoked whenever a single
  116. step interrupt occurs.    Locating the correct insertion point within
  117. DEBUG.COM is as simple as looking backwards from the interrupt vector
  118. stored at 0000:0004, the single step interrupt vector.    This interrupt
  119. vector is 0600:08ED for my version of DOS.  The segment value, 600,
  120. varies with the number of I/O buffers, whether there are other
  121. interrupt service routines resident below DEBUG, whether we are
  122. executing from within a BAT file or invoked directly from DOS, etc,
  123. etc.  The important piece of information obtained from this vector is
  124. 8ED, the offset relative to the start of DEBUG where we want to begin
  125. our code changes.
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135. File: DEBUGFIX.TXT                    Page 3
  136.  
  137.  
  138.  
  139. Within DEBUG at this offset is code to swap the stack and save all the
  140. registers.
  141.  
  142.     600:8ED     MOV    WORD PTR CS:[2AEA],SP
  143.     600:8F2     MOV    WORD PTR CS:[XXXX],SS
  144.  
  145. We will replace the MOV instruction at 8ED with a JMP to our special
  146. code.  When our code completes, we will execute the MOV instruction we
  147. have displaced and JMP back to 600:8F2.
  148.  
  149. We need to find a safe place in memory to insert 35 instructions
  150. within DEBUG.COM.  This is not easy without the source code.  We have
  151. chosen to insert the extra code into the location currently occupied
  152. by the user's program segment prefix.  In turn, the program segment
  153. prefix is pushed up in memory by 64 bytes.  The prefix must be on a
  154. paragraph boundary so the number of bytes stolen must be a multiple of
  155. 16.
  156.  
  157. The next logical step is to begin looking around inside DEBUG for
  158. an invocation of the DOS function 26h which builds the user's program
  159. segment prefix.  The DEBUG code at 600:138 asks DOS to build a program
  160. segment prefix at 600:2f20 but when the smoke clears and the user's
  161. program actually starts execution, the prefix has been moved to
  162. 600:2f60 and the area at 2f20 has been trashed.  Since we don't have
  163. DEBUG source, our only possible work around is to pad this area,
  164. soaking up 144 bytes to insert a patch less than 64 bytes long.
  165.  
  166. We modify DEBUG code at 600:138 from
  167.  
  168.     MOV  AX,2F17
  169. to
  170.     MOV  AX,2FA0
  171.  
  172. For good measure we use the DEBUG S (search) command to look around
  173. inside DEBUG.COM for any other occurrences of the string 2F17.    This
  174. search reveals a second place within DEBUG which must be changed, this
  175. time at 600:183 from
  176.  
  177.     MOV  BX,2F17
  178. to
  179.     MOV  BX,2FA0
  180.  
  181. The remaining modifications are straight-forward.  Modify the
  182. instruction pointed to by the single step interrupt vector (600:8ED)
  183. from
  184.  
  185.     MOV    WORD PTR CS:[2AEA],SP
  186. to
  187.     JMP    2F60
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201. File: DEBUGFIX.TXT                    Page 4
  202.  
  203.  
  204.  
  205. At 600:2F60 start adding our special instructions
  206.  
  207.     PUSH  BP
  208.     MOV   BP,SP
  209.     PUSH  AX
  210.     PUSH  BX
  211.     PUSH  CX
  212.     PUSH  DI
  213.     PUSH  ES
  214.     SUB   AX,AX
  215.     MOV   ES,AX
  216.     MOV   DI,20
  217.     MOV   AX,WORD PTR [BP+2]
  218.     MOV   BX,WORD PTR [BP+4]
  219.     MOV   CX,8
  220.     SCASW
  221.     JNE   2F8C
  222.     ES:CMP     BX,WORD PTR [DI]
  223.     JNE   2F8C
  224.     AND   WORD PTR [BP+6],FEFF
  225.     POP   ES
  226.     POP   DI
  227.     POP   CX
  228.     POP   BX
  229.     POP   AX
  230.     POP   BP
  231.     IRET
  232.  
  233. If the PUSH BP is at 2F60 then the following ADD is at 2F8C.
  234.  
  235.     ADD   DI,2
  236.     LOOP  2F78
  237.     POP   ES
  238.     POP   DI
  239.     POP   CX
  240.     POP   BX
  241.     POP   AX
  242.     POP   BP
  243.     CS:
  244.     MOV   [2AEA],SP
  245.     JMP   8F2
  246.  
  247. We set BP to point to the stack.  Since BP itself is now on the stack,
  248. the offsets listed earlier relative to SP are two bytes off.  We check
  249. the segment and offset stored on the stack to see if it is an external
  250. interrupt service routine.  If it isn't, we restore the registers,
  251. execute the instruction which used to be at 600:8ED, and JMP back to
  252. 600:8F2.  If it is an external interrupt, we clear the trap flag with
  253. the AND instruction, restore the registers, then IRET back to the
  254. interrupt service routine.
  255.  
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267. File: DEBUGFIX.TXT                    Page 5
  268.  
  269.  
  270.  
  271. As distributed, the DEBUG.COM file does not contain the temporary
  272. variables used by DEBUG during execution.  These variables reside
  273. between 600:2E80 (end of the DEBUG code) and 600:2F60 (eventual home
  274. of the user's program segment prefix).  Since we are storing our code
  275. at 2F60, we must enlarge the DEBUG.COM file to include our added code
  276. and the intervening temp space.
  277.  
  278. We modify DEBUG.COM using the DEBUG commands
  279.  
  280.     -n debug.com
  281.     -l
  282.  
  283. make the changes and then enlarge DEBUG.COM by writing back to disk
  284. more than we read
  285.  
  286.     -r cx
  287.     CX 2E80
  288.     :2FA0
  289.     -w
  290.     Writing 2FA0 bytes
  291.  
  292. The simplest means of propagating this fix to other interested users
  293. is to create a text file containing all the needed DEBUG commands,
  294. then use the TYPE command to put the text file into the pipeline and
  295. feed the commands to DEBUG itself.  If we put the following commands
  296. in a file named DEBUG20.FIX
  297.  
  298.     n debug.com
  299.     l
  300.     a 138
  301.     mov   ax,2fa0
  302.  
  303.     a 183
  304.     mov   bx,2fa0
  305.  
  306.     a 8ed
  307.     jmp   2f60
  308.  
  309.     a 2f60
  310.     push  bp
  311.     mov   bp,sp
  312.     push  ax
  313.     push  bx
  314.     push  cx
  315.     push  di
  316.     push  es
  317.     sub   ax,ax
  318.     mov   es,ax
  319.     mov   di,20
  320.     mov   ax,word ptr [bp+2]
  321.     mov   bx,word ptr [bp+4]
  322.     mov   cx,8
  323.     scasw
  324.    --------------- Code split for page separation. No blank lines here
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333. File: DEBUGFIX.TXT                    Page 6
  334.  
  335.  
  336.  
  337.  
  338.    --------------- Code split for page separation. No blank lines here
  339.     jne   2f8c
  340.     es:cmp     bx,word ptr [di]
  341.     jne   2f8c
  342.     and   word ptr [bp+6],feff
  343.     pop   es
  344.     pop   di
  345.     pop   cx
  346.     pop   bx
  347.     pop   ax
  348.     pop   bp
  349.     iret
  350.     add   di,2
  351.     loop  2f78
  352.     pop   es
  353.     pop   di
  354.     pop   cx
  355.     pop   bx
  356.     pop   ax
  357.     pop   bp
  358.     cs:mov [2aea],sp
  359.     jmp   08f2
  360.  
  361.     r cx
  362.     2fa0
  363.     w
  364.     q
  365.  
  366. Then with a copy of DEBUG.COM on the diskette in the default drive
  367. merely give the following pipelined command to DOS.
  368.  
  369.     TYPE  DEBUG20.FIX | DEBUG
  370.  
  371.  
  372. The blank lines within the DEBUG20.FIX file are needed for correct
  373. execution of the commands.  Once all the commands have executed, your
  374. DEBUG patch is complete.
  375.  
  376. The cost of the patch is a DEBUG.COM file which requires 288 more
  377. bytes to store on diskette and which consumes an extra 144 bytes of
  378. memory when executed.
  379.  
  380.